﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel.Configuration;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.Security.Principal;
using System.IdentityModel.Policy;
using System.IdentityModel.Claims;
using System.ServiceModel.Security;
using System.ServiceModel;
using System.Net;
using System.Xml;

namespace USTF.Media.MediaService.UmbracoDefault
{
    



    public class BasicAuthenticationBehavior : BehaviorExtensionElement, IEndpointBehavior
    {
        public override Type BehaviorType
        {
            get { return typeof(BasicAuthenticationBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new BasicAuthenticationBehavior();
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
           
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
           
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
            BasicAuthenticationInspector inspector = new BasicAuthenticationInspector();
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
        }

        public void Validate(ServiceEndpoint endpoint)
        {
            
        }
        public class AuthenticationFailure { }
        public class BasicAuthenticationInspector : IDispatchMessageInspector
        {
            public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
            {
                string[] credentials = ExtractCredentials(request);
                if (credentials.Length > 0 && AuthenticateUser(credentials[0], credentials[1]))
                {
                    InitializeSecurityContext(request, credentials[0]);
                }
                else
                {
                    request = null;
                    return new AuthenticationFailure();
                }
                return null;
            }

            public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
            {
                if (correlationState is AuthenticationFailure)
                {
                    HttpResponseMessageProperty responseProperty = new HttpResponseMessageProperty() { StatusCode = HttpStatusCode.Unauthorized };

                    responseProperty.Headers.Add("WWW-Authenticate",
                        String.Format("Basic realm=\"{0}\"", "foo"));

                    reply.Properties[HttpResponseMessageProperty.Name] = responseProperty;
                }
            }

            private void InitializeSecurityContext(Message request, string username)
            {
                GenericPrincipal principal = new GenericPrincipal(new GenericIdentity(username), new string[] { });

                List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>();
                policies.Add(new PrincipalAuthorizationPolicy(principal));
                ServiceSecurityContext securityContext = new ServiceSecurityContext(policies.AsReadOnly());

                if (request.Properties.Security != null)
                {
                    request.Properties.Security.ServiceSecurityContext = securityContext;
                }
                else
                {
                    request.Properties.Security = new SecurityMessageProperty() { ServiceSecurityContext = securityContext };
                }
            }

            class PrincipalAuthorizationPolicy : IAuthorizationPolicy
            {
                string id = Guid.NewGuid().ToString();
                IPrincipal user;

                public PrincipalAuthorizationPolicy(IPrincipal user)
                {
                    this.user = user;
                }

                public ClaimSet Issuer
                {
                    get { return ClaimSet.System; }
                }

                public string Id
                {
                    get { return this.id; }
                }

                public bool Evaluate(EvaluationContext evaluationContext, ref object state)
                {
                    evaluationContext.AddClaimSet(this, new DefaultClaimSet(Claim.CreateNameClaim(user.Identity.Name)));
                    evaluationContext.Properties["Identities"] = new List<IIdentity>(new IIdentity[] { user.Identity });
                    evaluationContext.Properties["Principal"] = user;
                    return true;
                }
            }

            private bool AuthenticateUser(string username, string password)
            {
                var tester = new FakeMediaWebService();

                try
                {
                    tester.Authenticate(username, password);
                }
                catch
                {
                    return false;
                    //throw new SecurityTokenException("Validation Failed!");
                }
                return true;
            }

            private string[] ExtractCredentials(Message requestMessage)
            {
                string authHeader = requestMessage.Headers.GetHeader<string>("SUMOAuth","SUMO");

                if (!String.IsNullOrEmpty(authHeader))
                {
                    //string authHeader = requestMessage.Headers.GetReaderAtHeader(authHeaderLocation).ReadContentAsString();
                    string encodedUserPass = authHeader.Substring(6).Trim();

                    //Encoding encoding = Encoding.GetEncoding("UTF-8");
                    //string userPass = encoding.GetString(Convert.FromBase64String(encodedUserPass));
                    int separator = encodedUserPass.IndexOf(':');

                    string[] credentials = new string[2];
                    credentials[0] = encodedUserPass.Substring(0, separator);
                    credentials[1] = encodedUserPass.Substring(separator + 1);

                    return credentials;
                }

                return new string[] { };
            }


        }
    }
}
